/*
Pong Mania- A 3D OpenGL pong game.
Copyright (C) 2001  Steve Wortham

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation version 2

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/



/*
 		Pong Mania
 		by: Steve Wortham
 		website: www.stevescomp.atfreeweb.com
 		email: steve.wortham@juno.com
 		
*/

#include <list>
#include <vector>
#include "regexpr2.h"
#include <string>
#include <time.h>
#include <stdlib.h>
#include <math.h>		// Header File For Windows
#include <windows.h>										// Header File For Windows
#include <stdio.h>											// Header File For Standard Input / Output
#include <stdarg.h>											// Header File For Variable Argument Routines
#include <gl\gl.h>											// Header File For The OpenGL32 Library
#include <gl\glu.h>											// Header File For The GLu32 Library
#include <gl\glaux.h>										// Header File For The Glaux Library
#include "ws-util.h" //networking support lib

#include <winsock.h> //networking library

#include <iostream>
#include <fstream>
#include <string.h>

#define XMAX 2.5
#define XMIN -2.5
#define YMAX 2.0
#define YMIN -1.75
#define MYPADDLEZ -6.0
#define OPPPADDLEZ -16.0

#pragma comment(lib, "wsock32")
#pragma comment(lib, "rasapi32")

using namespace std;
using namespace regex;

////////////////////////////////////////////////////////////////////////
// Constants
GLuint	base;
SOCKET sd;
// kBufferSize must be larger than the length of kpcEchoMessage.
const int kBufferSize = 1024;
const char* kpcEchoMessage = "!INCOMING!";
const int kEchoMessageLen = strlen(kpcEchoMessage);
int client_id = 0; //this will be the id to identify this client
ofstream debug;

#if defined(SHUTDOWN_DELAY)
// How long to wait after we do the echo before shutting the connection
// down, to give the user time to start other clients, for testing 
// multiple simultaneous connections.
const int kShutdownDelay = 3;
#endif

bool up;
bool dn;
bool rn;
bool esc;
//#include <windows.h>		// Header File For Windows
//#include <stdio.h>			// Header File For Standard Input/Output
//#include <gl\gl.h>			// Header File For The OpenGL32 Library
//#include <gl\glu.h>			// Header File For The GLu32 Library
//#include <gl\glaux.h>		// Header File For The Glaux Library

HDC		hDC=NULL;			// Private GDI Device Context
HGLRC	hRC=NULL;			// Permanent Rendering Context
HWND	hWnd=NULL;			// Holds Our Window Handle

bool DONE = false;
bool MENU = true;
bool flag = 0;			//Player 2
int dontbounce = 10;
int side = 0;			//0 for 1P, 1 for 2P
bool isServed = 0;

int item = 1;
bool Selection = false;
bool PlayAgain = true;
bool Options = false;
bool Exit = false;
bool newgame = true;

int score1 = 0;
int score2 = 0;

GLfloat x = 0;				//The ball's position
GLfloat y = 0;
GLfloat	z = -6.0f;			// Depth Into The Screen
GLfloat xOrigin = 0;
GLfloat zOrigin = -11.0f;
GLfloat xPrime = 0;
GLfloat zPrime = z-zOrigin;

GLfloat xp = 0;//1;				//The ball's speed
GLfloat yp = 0;//.9f;
GLfloat zp = 0;//3.0f;

GLfloat mx = 0;				//Our paddle's location
GLfloat my = YMIN+0.5f;
GLfloat mz = MYPADDLEZ;
GLfloat mxp = 0;			//Irrelevant (used to be transitional speed)
GLfloat myp = 0;
GLfloat mzp = 0;
GLfloat mxOrigin = mx;
GLfloat mxPrime = 0;
GLfloat mColor = 1;

GLfloat cmx = 0;			//Opponent's paddle's location
GLfloat cmy = YMIN+0.5f;
GLfloat cmz = OPPPADDLEZ;
GLfloat cmxp = 0;			//Also irrelevant (used to be transitional speed)
GLfloat cmyp = 0;
GLfloat cmzp = 0;
GLfloat cmxOrigin = cmx;
GLfloat cmxPrime = 0;
GLfloat cmColor = 1;

GLfloat r = 0;
GLfloat g = 0;
GLfloat b = 0;    

GLfloat	xrot;				// X Rotation
GLfloat	yrot;				// Y Rotation
GLfloat	zrot;				// Y Rotation
GLfloat xspeed = 0;				// X Rotation Speed
GLfloat yspeed = 0;				// Y Rotation Speed
GLfloat zspeed = 0;				// Y Rotation Speed

GLfloat RoomZrot = 0;

//GLfloat Dist;
//GLfloat cDist;
//GLfloat Speed;

int cntclr = 0;

float alpha1=.25f;
float alpha2=.25f;
float alpha3=.25f;
float alpha1a=0;
float alpha2a=0;
float alpha3a=0;
float alpha1ap=0;
float alpha2ap=0;
float alpha3ap=0;

float menuZ = 0;


bool	keys[256];			// Array Used For The Keyboard Routine
bool	active=TRUE;		// Window Active Flag Set To TRUE By Default
bool	fullscreen=TRUE;	// Fullscreen Flag Set To Fullscreen Mode By Default

GLUquadricObj *quadratic;	// Storage For Our Quadratic Objects ( NEW )

//zany networking function

GLvoid BuildFont(GLvoid)								// Build Our Bitmap Font
{
	HFONT	font;										// Windows Font ID
	HFONT	oldfont;									// Used For Good House Keeping

	base = glGenLists(96);								// Storage For 96 Characters

	font = CreateFont(	-24,							// Height Of Font
						0,								// Width Of Font
						0,								// Angle Of Escapement
						0,								// Orientation Angle
						FW_BOLD,						// Font Weight
						FALSE,							// Italic
						FALSE,							// Underline
						FALSE,							// Strikeout
						ANSI_CHARSET,					// Character Set Identifier
						OUT_TT_PRECIS,					// Output Precision
						CLIP_DEFAULT_PRECIS,			// Clipping Precision
						ANTIALIASED_QUALITY,			// Output Quality
						FF_DONTCARE|DEFAULT_PITCH,		// Family And Pitch
						"Courier New");					// Font Name

	oldfont = (HFONT)SelectObject(hDC, font);           // Selects The Font We Want
	wglUseFontBitmaps(hDC, 32, 96, base);				// Builds 96 Characters Starting At Character 32
	SelectObject(hDC, oldfont);							// Selects The Font We Want
	DeleteObject(font);									// Delete The Font
}

GLvoid KillFont(GLvoid)									// Delete The Font List
{
	glDeleteLists(base, 96);							// Delete All 96 Characters
}

GLvoid glPrint(const char *fmt, ...)					// Custom GL "Print" Routine
{
	char		text[256];								// Holds Our String
	va_list		ap;										// Pointer To List Of Arguments

	if (fmt == NULL)									// If There's No Text
		return;											// Do Nothing

	va_start(ap, fmt);									// Parses The String For Variables
	    vsprintf(text, fmt, ap);						// And Converts Symbols To Actual Numbers
	va_end(ap);											// Results Are Stored In Text

	glPushAttrib(GL_LIST_BIT);							// Pushes The Display List Bits
	glListBase(base - 32);								// Sets The Base Character to 32
	glCallLists(strlen(text), GL_UNSIGNED_BYTE, text);	// Draws The Display List Text
	glPopAttrib();										// Pops The Display List Bits
}

//convert float to string
char*   ftoa( double f, double sigfigs )
    {
    char a[81];
    int prec, width, front, fit;

    front = (f==0)? 1 : (int)log10(fabs(f))+1;
    if ( sigfigs < 1.0 && sigfigs >= 0.0 )  // fit number to tolerance
        {
        double rem = fabs(f) - int(f);
        prec=0;
        int num = (int)rem;
        while ( rem*pow(10,prec) - num > sigfigs )
            num = int(rem*pow(10,++prec));
        width = front;
        sprintf(a, "%#*.*f", width, prec, f );
        }
    else
        {
        if ( sigfigs < 2.0 ) sigfigs = 2.0;
            
        if ( front > (int)sigfigs )
            {
            sprintf( a, "%#.*e", (int)sigfigs-1, f );
            }
        else
            {
            prec = (int)sigfigs - front;
            if ( f==0.0 ) width = 2;
            else width = front + prec + 1;
            sprintf( a, "%#*.*f", width, prec, f );
            }
        }
    return strdup(a);
    }

SOCKET EstablishConnection(u_long nRemoteAddr, u_short nPort)
{
    // Create a stream socket
    SOCKET sd = socket(AF_INET, SOCK_STREAM, 0);
    if (sd != INVALID_SOCKET) {
        sockaddr_in sinRemote;
        sinRemote.sin_family = AF_INET;
        sinRemote.sin_addr.s_addr = nRemoteAddr;
        sinRemote.sin_port = nPort;
        if (connect(sd, (sockaddr*)&sinRemote, sizeof(sockaddr_in)) ==
                SOCKET_ERROR) {
            sd = INVALID_SOCKET;
        }
    }

    return sd;
}

//get info from server
string ReadReply(SOCKET sd)
{
    // Read reply from server
    char acReadBuffer[kBufferSize];
    int nTotalBytes = 0;
    while (nTotalBytes < kEchoMessageLen) {
        int nNewBytes = recv(sd, acReadBuffer + nTotalBytes, 
                kBufferSize - nTotalBytes, 0);
        if (nNewBytes == SOCKET_ERROR) {
            cerr<<"ugh"<<endl;
			exit(0);
        }
        else if (nNewBytes == 0) {
            cerr << "Connection closed by peer." << endl;
            exit(0);
        }

        nTotalBytes += nNewBytes;
    }

    string str(acReadBuffer);
	return str;
}

// Absolute value function(comes in handy later).
inline GLfloat ABS(GLfloat A)
{
  if (A < 0)
  A = -A; 
  return A;
}
// Hypotenuse Function
inline GLfloat Hypot(GLfloat a, GLfloat b)
{
  return sqrt((a*a)+(b*b));
}

GLfloat LightAmbient[]=		{ 0.2f, 0.2f, 0.2f, 1.0f };
GLfloat LightDiffuse[]=		{ 0.5f, 0.5f, 0.5f, 1.0f };
GLfloat LightSpecular[]=	{ 1.0f, 1.0f, 1.0f, 1.0f };
GLfloat LightPosition[]=	{ 0.0f, 0.0f, -11.0f, 1.0f };

GLuint	fogMode[]= { GL_EXP, GL_EXP2, GL_LINEAR };	// Storage For Three Types Of Fog
GLuint	fogfilter = 0;								// Which Fog Mode To Use 
GLfloat	fogColor[4] = {.7f, .7f, .8f, 0};		            // Fog Color

GLuint	filter;				// Which Filter To Use
GLuint	texture[15];			// Storage For 3 Textures
GLuint  object=0;			// Which Object To Draw (NEW)

LRESULT	CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);	// Declaration For WndProc


								// Storage For 96 Characters
// Create A Structure For The Timer Information
struct
{
  __int64       frequency;          // Timer Frequency
  float            resolution;          // Timer Resolution
  unsigned long mm_timer_start;     
  
  // Multimedia Timer Start Value
  unsigned long mm_timer_elapsed;      // Multimedia Timer Elapsed Time
  bool   performance_timer;    
  
  // Using The Performance Timer?
  __int64       performance_timer_start;      // Performance Timer Start Value
  __int64       performance_timer_elapsed; // Performance Timer Elapsed Time
} timer;

// Initialize Our Timer
void TimerInit(void)
{
     memset(&timer, 0, sizeof(timer));   
 // Clear Our Timer Structure
     // Check To See If A Performance Counter Is Available
     // If One Is Available The Timer Frequency Will Be Updated
     if (!QueryPerformanceFrequency((LARGE_INTEGER *) &timer.frequency))
     {
          // No Performace Counter Available
          timer.performance_timer = FALSE;                      // Set Performance Timer To FALSE
          timer.mm_timer_start = timeGetTime();                 // Use timeGetTime()
          timer.resolution  = 1.0f/1000.0f;                           // Set Our Timer Resolution To .001f
          timer.frequency   = 1000;                                     // Set Our Timer Frequency To 1000
          timer.mm_timer_elapsed = timer.mm_timer_start; // Set The Elapsed Time
     }
     else
     {
          // Performance Counter Is Available, Use It Instead Of The Multimedia Timer
          // Get The Current Time And Store It In performance_timer_start
          QueryPerformanceCounter((LARGE_INTEGER *) &timer.performance_timer_start);
          timer.performance_timer   = TRUE;    // Set Performance Timer To TRUE
          // Calculate The Timer Resolution Using The Timer Frequency
          timer.resolution    = (float) (((double)1.0f)/((double)timer.frequency));
          // Set The Elapsed Time To The Current Time
          timer.performance_timer_elapsed = timer.performance_timer_start;
     }
}

// Get Time In Milliseconds
float TimerGetTime()
{
     __int64 time;                                  // 'time' Will Hold A 64 Bit Integer
     if (timer.performance_timer)           // Are We Using The Performance Timer?
     {
          QueryPerformanceCounter((LARGE_INTEGER *) &time); // Current Performance Time
          // Return The Time Elapsed since TimerInit was called
          return ( (float) ( time - timer.performance_timer_start) * timer.resolution)*1000.0f;
     }
     else
     {
          // Return The Time Elapsed since TimerInit was called
          return ( (float) ( timeGetTime() - timer.mm_timer_start) * timer.resolution)*1000.0f;
     }
}


AUX_RGBImageRec *LoadBMP(char *Filename)				// Loads A Bitmap Image
{
	FILE *File=NULL;									// File Handle

	if (!Filename)										// Make Sure A Filename Was Given
	{
		return NULL;									// If Not Return NULL
	}

	File=fopen(Filename,"r");							// Check To See If The File Exists

	if (File)											// Does The File Exist?
	{
		fclose(File);									// Close The Handle
		return auxDIBImageLoad(Filename);				// Load The Bitmap And Return A Pointer
	}

	return NULL;										// If Load Failed Return NULL
}

int LoadGLTextures()									// Load Bitmaps And Convert To Textures
{
	int Status=FALSE;									// Status Indicator

	AUX_RGBImageRec *TextureImage[1];					// Create Storage Space For The Texture

	memset(TextureImage,0,sizeof(void *)*1);           	// Set The Pointer To NULL

	// Load The Bitmap, Check For Errors, If Bitmap's Not Found Quit
	if (TextureImage[0]=LoadBMP("texture/BlueGrain.bmp")) //"Data/Wall.bmp"))
	{
		Status=TRUE;									// Set The Status To TRUE

		glGenTextures(1, &texture[0]);					// Create Three Textures

		// Create MipMapped Texture
		glBindTexture(GL_TEXTURE_2D, texture[0]);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
		gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
	}

	if (TextureImage[0])								// If Texture Exists
	{
		if (TextureImage[0]->data)						// If Texture Image Exists
		{
			free(TextureImage[0]->data);				// Free The Texture Image Memory
		}

		free(TextureImage[0]);							// Free The Image Structure
	}

	// Load The Bitmap, Check For Errors, If Bitmap's Not Found Quit
	if (TextureImage[0]=LoadBMP("texture/wood5.bmp"))//data/cube.bmp")) //"Data/Wall.bmp"))
	{
		Status=TRUE;									// Set The Status To TRUE

		glGenTextures(1, &texture[1]);					// Create Three Textures

		// Create MipMapped Texture
		glBindTexture(GL_TEXTURE_2D, texture[1]);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
		gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
	}

	if (TextureImage[0])								// If Texture Exists
	{
		if (TextureImage[0]->data)						// If Texture Image Exists
		{
			free(TextureImage[0]->data);				// Free The Texture Image Memory
		}

		free(TextureImage[0]);							// Free The Image Structure
	}


	// Load The Bitmap, Check For Errors, If Bitmap's Not Found Quit
	if (TextureImage[0]=LoadBMP("texture/asphalt.bmp"))//data/bricksgreen.bmp")) //"Data/Wall.bmp"))
	{
		Status=TRUE;									// Set The Status To TRUE

		glGenTextures(1, &texture[2]);					// Create Three Textures

		// Create MipMapped Texture
		glBindTexture(GL_TEXTURE_2D, texture[2]);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
		gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
	}

	if (TextureImage[0])								// If Texture Exists
	{
		if (TextureImage[0]->data)						// If Texture Image Exists
		{
			free(TextureImage[0]->data);				// Free The Texture Image Memory
		}

		free(TextureImage[0]);							// Free The Image Structure
	}


/*	// Load The Bitmap, Check For Errors, If Bitmap's Not Found Quit
	if (TextureImage[0]=LoadBMP("texture/wood2_red.bmp"))//data/bricksred.bmp")) //"Data/Wall.bmp"))
	{
		Status=TRUE;									// Set The Status To TRUE

		glGenTextures(1, &texture[3]);					// Create Three Textures

		// Create MipMapped Texture
		glBindTexture(GL_TEXTURE_2D, texture[3]);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
		gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
	}

	if (TextureImage[0])								// If Texture Exists
	{
		if (TextureImage[0]->data)						// If Texture Image Exists
		{
			free(TextureImage[0]->data);				// Free The Texture Image Memory
		}

		free(TextureImage[0]);							// Free The Image Structure
	}
*/
	// Load The Bitmap, Check For Errors, If Bitmap's Not Found Quit
	if (TextureImage[0]=LoadBMP("texture/wood4.bmp"))//data/bricksred.bmp")) //"Data/Wall.bmp"))
	{
		Status=TRUE;									// Set The Status To TRUE

		glGenTextures(1, &texture[4]);					// Create Three Textures

		// Create MipMapped Texture
		glBindTexture(GL_TEXTURE_2D, texture[4]);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
		gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
	}

	if (TextureImage[0])								// If Texture Exists
	{
		if (TextureImage[0]->data)						// If Texture Image Exists
		{
			free(TextureImage[0]->data);				// Free The Texture Image Memory
		}

		free(TextureImage[0]);							// Free The Image Structure
	}

	// Load The Bitmap, Check For Errors, If Bitmap's Not Found Quit
	if (TextureImage[0]=LoadBMP("texture/PlayAgain.bmp"))//data/bricksred.bmp")) //"Data/Wall.bmp"))
	{
		Status=TRUE;									// Set The Status To TRUE

		glGenTextures(1, &texture[5]);					// Create Three Textures

		// Create MipMapped Texture
		glBindTexture(GL_TEXTURE_2D, texture[5]);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
		gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
	}

	if (TextureImage[0])								// If Texture Exists
	{
		if (TextureImage[0]->data)						// If Texture Image Exists
		{
			free(TextureImage[0]->data);				// Free The Texture Image Memory
		}

		free(TextureImage[0]);							// Free The Image Structure
	}

	// Load The Bitmap, Check For Errors, If Bitmap's Not Found Quit
	if (TextureImage[0]=LoadBMP("texture/Options.bmp"))//data/bricksred.bmp")) //"Data/Wall.bmp"))
	{
		Status=TRUE;									// Set The Status To TRUE

		glGenTextures(1, &texture[6]);					// Create Three Textures

		// Create MipMapped Texture
		glBindTexture(GL_TEXTURE_2D, texture[6]);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
		gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
	}

	if (TextureImage[0])								// If Texture Exists
	{
		if (TextureImage[0]->data)						// If Texture Image Exists
		{
			free(TextureImage[0]->data);				// Free The Texture Image Memory
		}

		free(TextureImage[0]);							// Free The Image Structure
	}

	// Load The Bitmap, Check For Errors, If Bitmap's Not Found Quit
	if (TextureImage[0]=LoadBMP("texture/Exit.bmp"))//data/bricksred.bmp")) //"Data/Wall.bmp"))
	{
		Status=TRUE;									// Set The Status To TRUE

		glGenTextures(1, &texture[7]);					// Create Three Textures

		// Create MipMapped Texture
		glBindTexture(GL_TEXTURE_2D, texture[7]);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
		gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
	}

	if (TextureImage[0])								// If Texture Exists
	{
		if (TextureImage[0]->data)						// If Texture Image Exists
		{
			free(TextureImage[0]->data);				// Free The Texture Image Memory
		}

		free(TextureImage[0]);							// Free The Image Structure
	}

	return Status;										// Return The Status
}

GLvoid ReSizeGLScene(GLsizei width, GLsizei height)		// Resize And Initialize The GL Window
{
	if (height==0)										// Prevent A Divide By Zero By
	{
		height=1;										// Making Height Equal One
	}

	glViewport(0,0,width,height);						// Reset The Current Viewport

	glMatrixMode(GL_PROJECTION);						// Select The Projection Matrix
	glLoadIdentity();									// Reset The Projection Matrix

	// Calculate The Aspect Ratio Of The Window
	gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.5f,100.0f);

	glMatrixMode(GL_MODELVIEW);							// Select The Modelview Matrix
	glLoadIdentity();									// Reset The Modelview Matrix
}


int frames = 0;

float Time1;
float Time2;
float DiffTime;
float FrameRate = 1;
float FrameRatep = 0;
float OverallSpeed = FrameRate;

void Benchmark()
{
//FPS /////////////////////////////
///////////////////////////////////
//
    int repeat = 50;
    Time1 = TimerGetTime()/1000;
    glLoadIdentity();
    glTranslatef(0,0,0);
    
    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);	// Clear The Screen And The Depth Buffer         
    SwapBuffers(hDC);
    glEnable(GL_BLEND);
    for(float cnt = 0; cnt < repeat; cnt+=.1f)
    {
      glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);	// Clear The Screen And The Depth Buffer         
      glRotatef(cnt,1,0,0);
      glColor4f(1,1,1,cnt/10);
      glBegin(GL_TRIANGLE_STRIP);
      glTexCoord2f(1,1); glVertex3f(cnt+1,cnt+1,-20); 
      glTexCoord2f(1,0); glVertex3f(cnt+1,cnt,-20);
      glTexCoord2f(0,1); glVertex3f(cnt,cnt+1,-20);
      glTexCoord2f(0,0); glVertex3f(cnt,cnt,-20);
      glEnd();
      SwapBuffers(hDC);
    }  
    glDisable(GL_BLEND);
    
    Time2 = TimerGetTime()/1000;
    DiffTime = ABS(Time2-Time1);    
}

int InitGL(GLvoid)										// All Setup For OpenGL Goes Here
{
	if (!LoadGLTextures())								// Jump To Texture Loading Routine
	{
		return FALSE;									// If Texture Didn't Load Return FALSE
	}

	glEnable(GL_TEXTURE_2D);							// Enable Texture Mapping

	glClearColor(0.0f, 0.0f, 0.0f, 1.0f);				// Background Color
	glClearDepth(1.0f);		
    							// Depth Buffer Setup   
	glEnable(GL_DEPTH_TEST);
  glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);					// Type Of Blending To Perform

	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);	// Really Nice Perspective Calculations

	quadratic=gluNewQuadric();							// Create A Pointer To The Quadric Object (Return 0 If No Memory) (NEW)
	gluQuadricNormals(quadratic, GLU_SMOOTH);			// Create Smooth Normals (NEW)
	gluQuadricTexture(quadratic, GL_TRUE);				// Create Texture Coords (NEW)

  TimerInit();
  BuildFont();
//Benchmark();       

//  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	return TRUE;										// Initialization Went OK
}

void GameInit()
{
	if (flag)
	{
		if (side == 1)
		{
			x = 0;				//The ball's position
			y = 0;
			z = -16.0f;			// Depth Into The Screen
		}
		else
		{
			x = 0;
			y = 0;
			z = -6.0f;
		}
	}

    xp = 0;
    yp = 0;
    zp = 0;
	dontbounce = 30;				//makes for not-buggy serving
	isServed = 0;				//ball has NOT been served

    mx = 0;				//Our paddle's location
    my = YMIN+0.5f;
    mz = MYPADDLEZ;
    mxp = 0;			//Irrelevant (used to be transitional speed)
    myp = 0;
    mzp = 0;
	mxPrime = 0;

	cmx = 0;			//Opponent's paddle's location
	cmy = YMIN+0.5f;
	cmz = OPPPADDLEZ;
	cmxp = 0;			//Also irrelevant (used to be transitional speed)
	cmyp = 0;
	cmzp = 0;
	cmxPrime = 0;
}

void Menu()
{    
    if (PlayAgain)
    {     
      alpha1+=.025f;
      alpha2-=.010f;
      alpha3-=.010f;
      if(alpha1 >   .75f) alpha1 = .75f;
      if(alpha2 < .5f) alpha2 = .5f;
      if(alpha3 < .5f) alpha3 = .5f;
      alpha1ap += .5f-alpha1a;
      alpha1a += alpha1ap/250;
      alpha2a=0; alpha2ap=0; alpha3a=0; alpha3ap=0;
    }
    else if (Options)
    {
      alpha1-=.010f;
      alpha2+=.025f;
      alpha3-=.010f;
      if(alpha1 < .5f) alpha1 = .5f;
      if(alpha2 >  .75f) alpha2 = .75f;
      if(alpha3 < .5f) alpha3 = .5f;
      alpha2ap += .5f-alpha2a;
      alpha2a += alpha2ap/250;
      alpha1a=0; alpha1ap=0; alpha3a=0; alpha3ap=0;
    }
    else if (Exit)
    {
      alpha1-=.010f;
      alpha2-=.010f;
      alpha3+=.025f;
      if(alpha1 < .5f) alpha1 = .5f;
      if(alpha2 < .5f) alpha2 = .5f;
      if(alpha3 > .75f) alpha3 = .75f;
      alpha3ap += .5f-alpha3a;
      alpha3a += alpha3ap/250;
      alpha1a=0; alpha1ap=0; alpha2a=0; alpha2ap=0;
    }
     
    glEnable(GL_BLEND);
    glDisable(GL_DEPTH_TEST);
//    glDisable(GL_LIGHTING);

    int scalemenu = 2;
       
    menuZ-=.1f;
    if (menuZ < -9) menuZ = -9;
    
    glLoadIdentity();
    glTranslatef(0,0,menuZ-1);    

//Backdrop
    glBindTexture(GL_TEXTURE_2D,texture[2]);
    glColor4f(0,0,1,1.f);
    glBegin(GL_TRIANGLE_STRIP);
    glTexCoord2f(1,1); glVertex3f( 1.0f*scalemenu, (.8f)*scalemenu,0);
    glTexCoord2f(1,0); glVertex3f( 1.0f*scalemenu, (-.4f)*scalemenu,0);
    glTexCoord2f(0,1); glVertex3f(-1.0f*scalemenu, (.8f)*scalemenu,0);
    glTexCoord2f(0,0); glVertex3f(-1.0f*scalemenu, (-.4f)*scalemenu,0);
    glEnd();   


    glBindTexture(GL_TEXTURE_2D,texture[5]);
    glColor4f(1,1,1,(alpha1+alpha1a)/2);
    glBegin(GL_TRIANGLE_STRIP);
    glTexCoord2f(1,1); glVertex3f( 1.0f*scalemenu,(.4f+.4f)*scalemenu,0);
    glTexCoord2f(1,0); glVertex3f( 1.0f*scalemenu,   .4f*scalemenu,0);
    glTexCoord2f(0,1); glVertex3f(-1.0f*scalemenu,(.4f+.4f)*scalemenu,0);
    glTexCoord2f(0,0); glVertex3f(-1.0f*scalemenu,   .4f*scalemenu,0);
    glEnd();  
    
    /*glColor4f(.5f,.5f,alpha1a,.5f);
    glBegin(GL_TRIANGLE_STRIP);
    glTexCoord2f(1,1); glVertex3f( 1.0*scalemenu, (.4+.4)*scalemenu,0);
    glTexCoord2f(1,0); glVertex3f( 1.0*scalemenu,    .4*scalemenu,0);
    glTexCoord2f(0,1); glVertex3f(-1.0*scalemenu, (.4+.4)*scalemenu,0);
    glTexCoord2f(0,0); glVertex3f(-1.0*scalemenu,    .4*scalemenu,0);
    glEnd();  
    */
    glBindTexture(GL_TEXTURE_2D,texture[6]);
    glColor4f(1,1,1,(alpha2+alpha2a)/2);
    glBegin(GL_TRIANGLE_STRIP);
    glTexCoord2f(1,1); glVertex3f( 1.0f*scalemenu, .4f*scalemenu,0);
    glTexCoord2f(1,0); glVertex3f( 1.0f*scalemenu,  0,0);
    glTexCoord2f(0,1); glVertex3f(-1.0f*scalemenu, .4f*scalemenu,0);
    glTexCoord2f(0,0); glVertex3f(-1.0f*scalemenu,  0,0);
    glEnd();   
    
    /*glColor4f(.5f,.5f,alpha2a,.5f);
    glBegin(GL_TRIANGLE_STRIP);
    glTexCoord2f(1,1); glVertex3f( 1.0*scalemenu, .4*scalemenu,0);
    glTexCoord2f(1,0); glVertex3f( 1.0*scalemenu,  0,0);
    glTexCoord2f(0,1); glVertex3f(-1.0*scalemenu, .4*scalemenu,0);
    glTexCoord2f(0,0); glVertex3f(-1.0*scalemenu,  0,0);
    glEnd();*/

    glBindTexture(GL_TEXTURE_2D,texture[7]);
    glColor4f(1,1,1,(alpha3+alpha3a)/2);
    glBegin(GL_TRIANGLE_STRIP);
    glTexCoord2f(1,1); glVertex3f( 1.0f*scalemenu, (.4f-.4f)*scalemenu,0);
    glTexCoord2f(1,0); glVertex3f( 1.0f*scalemenu, (0-.4f)*scalemenu,0);
    glTexCoord2f(0,1); glVertex3f(-1.0f*scalemenu, (.4f-.4f)*scalemenu,0);
    glTexCoord2f(0,0); glVertex3f(-1.0f*scalemenu, (0-.4f)*scalemenu,0);
    glEnd();   
    
    /*glColor4f(.5f,.5f,alpha3a,.5f);
    glBegin(GL_TRIANGLE_STRIP);
    glTexCoord2f(1,1); glVertex3f( 1.0*scalemenu, (.4-.4)*scalemenu,0);
    glTexCoord2f(1,0); glVertex3f( 1.0*scalemenu, (0-.4)*scalemenu,0);
    glTexCoord2f(0,1); glVertex3f(-1.0*scalemenu, (.4-.4)*scalemenu,0);
    glTexCoord2f(0,0); glVertex3f(-1.0*scalemenu, (0-.4)*scalemenu,0);
    glEnd();*/
    //glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);  
	//  glEnable(GL_LIGHTING);
    glEnable(GL_DEPTH_TEST); 
}

bool WallXHit()
{
	if ((x+0.05f) >= (float)XMAX)
	{
		x = (float)XMAX-0.05f;
		return 1;
	}
	else if ((x-0.05f) <= (float)XMIN)
	{
		x = (float)XMIN+0.05f;
		return 1;
	}
	else
		return 0;
}

bool WallYHit()
{
	if ((y+0.05f) >= (float)YMAX)
	{
		y = (float)YMAX-0.05f;
		return 1;
	}
	else if ((y-0.05f) <= (float)YMIN)
	{
		y = (float)YMIN+0.05f;
		return 1;
	}
	else
		return 0;
}

bool MyPaddleHitX()
{
	if ((((x-0.25f) >= (mx-0.5f)) && ((x-0.25f) <= (mx+0.5f))) || (((x+0.25f) >= (mx-0.5f)) && ((x+0.25f) <= (mx+0.5f))))
		return 1;
	else
		return 0;
}

bool OppPaddleHitX()
{
	if ((((x-0.25f) >= (cmx-0.5f)) && ((x-0.25f) <= (cmx+0.5f))) || (((x+0.25f) >= (cmx-0.5f)) && ((x+0.25f) <= (cmx+0.5f))))
		return 1;
	else
		return 0;
}

bool MyPaddleHitY()
{
	if ((((y-0.25f) >= (my-0.5f)) && ((y-0.25f) <= (my+0.5f))) || (((y+0.25f) >= (my-0.5f)) && ((y+0.25f) <= (my+0.5f))))
		return 1;
	else
		return 0;
}

bool OppPaddleHitY()
{
	if ((((y-0.25f) >= (cmy-0.5f)) && ((y-0.25f) <= (cmy+0.5f))) || (((y+0.25f) >= (cmy-0.5f)) && ((y+0.25f) <= (cmy+0.5f))))
		return 1;
	else
		return 0;
}

bool MyPaddleHitZ()
{
	if ((mz >= (z-0.25f)) && (mz <= (z+0.25f)))
		return 1;
	else
		return 0;
}

bool OppPaddleHitZ()
{
	if ((cmz >= (z-0.25f)) && (cmz <= (z+0.25f)))
		return 1;
	else
		return 0;
}

bool MyPaddleHit()
{
	if ((MyPaddleHitX() && MyPaddleHitY()) && MyPaddleHitZ())
		return 1;
	else
		return 0;
}

bool OppPaddleHit()
{
	if ((OppPaddleHitX() && OppPaddleHitY()) && OppPaddleHitZ())
		return 1;
	else
		return 0;
}

int Packets()
{
	mxPrime = mx-mxOrigin;
	xPrime = x-xOrigin;
	zPrime = z-zOrigin;

	cout<<"DRAWIN DIS"<<endl;
	//packet format: !ball_x:bally_y:ball_z:id:mx:my:mz!   sends the position of the current player's paddle
	char *temp;
	temp = new char[32];
	string mypacket;
	itoa(client_id, temp, 10);
	mypacket.append(temp);
	mypacket.append(":");
	if (MENU)
		mypacket.append("1");
	else
		mypacket.append("0");
	mypacket.append(":");
	mypacket.append(ftoa(mxPrime, 4));
	mypacket.append(":");
	mypacket.append(ftoa(my, 4));
	mypacket.append(":");
	mypacket.append(ftoa(xPrime, 4));
	mypacket.append(":");
	mypacket.append(ftoa(y, 4));
	mypacket.append(":");
	mypacket.append(ftoa(zPrime, 4));
	mypacket.append(":");
	mypacket.append(ftoa((float)score1, 4));
	mypacket.append(":");
	mypacket.append(ftoa((float)score2, 4));
	mypacket.append(":");
	mypacket.append("!");
	const int packetLen = int(mypacket.length());
	if (send(sd, mypacket.c_str(), packetLen, 0) == SOCKET_ERROR) {
		delete [] temp;
		return 4;
	}

	string incoming_packet(ReadReply(sd));
	split_results results;
	rpattern pat(":");
	string::iterator beginning = incoming_packet.begin();
	string::iterator ending = incoming_packet.end();
	pat.split(beginning, ending, results);
	vector<string> parsed_results = results.strings();
	//parse up result here
	vector<string>::iterator parser;
	parser = parsed_results.begin();
	
	if(strcmp("1P", parser->c_str()) == 0)
	{
		flag = 1;		//I must be 1P, since 1P is returned
		parser++;		//go to junk
	}
	else if(atoi(parser->c_str()) != client_id)
	{
		 parser++;						//this takes you to MENU status
		 MENU = atoi(parser->c_str());

		parser++;							//Looks for mxPrime
		 cmx = cmxOrigin - atof(parser->c_str());

		 parser++;							//Looks for my
		 cmy = atof(parser->c_str());

		 parser++;							//Looks for xPrime
		 if (flag == 0)
			 x = xOrigin - atof(parser->c_str());

		 parser++;							//Looks for y
		 if (flag == 0)
			 y = atof(parser->c_str());

		 parser++;							//Looks for zPrime
		 if (flag == 0)
			 z = zOrigin - atof(parser->c_str());

		 parser++;							//Looks for score1

		 debug << "The scores" << endl;
		 
		 if (flag == 0)
			 score2 = (int)atof(parser->c_str());

		 parser++;							//Looks for score2
		 if(flag == 0)
			 score1 = (int)atof(parser->c_str());

		 debug << "Scores obtained succesfully" << endl;

		 parser++; //go to junk
	}
	if(parser == parsed_results.end())
	{
		debug<<"OK"<<endl;
	}
	delete [] temp;
	return 1;
	  //debug<<temp_string<<endl;
}

bool ServeTheBall()
{
	if ((xp == 0) && (yp == 0) && (zp == 0))
	{
		if (MyPaddleHit())			//I serve
		{
			if (flag == 1)
			{
				xp = 0.2f+(0.4f-0.2f)*rand()/(float(RAND_MAX)+1);				//The ball's speed
				yp = 0.3f+(0.4f-0.3f)*rand()/(float(RAND_MAX)+1);
				zp = -2.0f+(-1.5f-(-2.0f))*rand()/(float(RAND_MAX)+1);
				if (rand()%2 == 0)
				{
					xp = -xp;
					yp = -yp;
				}
			}
			isServed = 1;
			mColor = 0;
			return 1;
		}
		else if (OppPaddleHit())			//I serve
		{
			if (flag == 1)
			{
				xp = 0.2f+(0.4f-0.2f)*rand()/(float(RAND_MAX)+1);				//The ball's speed
				yp = 0.3f+(0.4f-0.3f)*rand()/(float(RAND_MAX)+1);
				zp = 1.5f+(2.0f-1.5f)*rand()/(float(RAND_MAX)+1);
				if (rand()%2 == 0)
				{
					xp = -xp;
					yp = -yp;
				}
			}
			isServed = 1;
			cmColor = 0;
			return 1;
		}
		else
			return 0;
	}
	else
		return 0;
}

int DrawGLScene(GLvoid)									// Here's Where We Do All The Drawing
{
	char *temp;
	temp = new char[32];
	Packets();
 // debug.close();
  glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);	// Clear The Screen And The Depth Buffer

  glLoadIdentity();									// Reset The View
	
  if(!MENU)
  {   
	  if (!ServeTheBall())
	  {
		xp *= 1.00051f;
		yp *= 1.00051f;
		zp *= 1.00051f;
	  }

    r-=.01f;
    g-=.01f;
    if (r < 0) r = 0; 
    if (g < 0) g = 0; 

    if (flag)
	{
		if (z > -3)				//This tells me if the ball rolled past me; it then prepares the ball to launch again
		{
//			flag = !flag;
			side = !side;
			score2++;
			GameInit();
		}
		else if (z < -19)		//This tells me if the ball rolled past my opponent; it then prepares the ball to launch again
		{
			//PlaySound("youwin.wav", NULL, SND_SYNC);
			//		flag = !flag;
			side = !side;;
			score1++;
			GameInit();
		}
    } 

	if((score1>=5) || (score2>=5))
	{
		//This restarts the game
		newgame = 1;
		menuZ=0;
		MENU=true;
	}
	if (MyPaddleHit())
	{
		//PlaySound("tennis.wav", NULL, SND_ASYNC);
		if (dontbounce == 0)
		{
			mColor = 0;
			zp = -zp;
			dontbounce = 5;
		}
	}
	if (OppPaddleHit())
	{
		if (dontbounce == 0)
		{
			cmColor = 0;
			zp = -zp;
			dontbounce = 5;
		}
	}
	if (WallXHit())
	{
		xp = -xp;
		//PlaySound("tennis.wav", NULL, SND_ASYNC);
	}
	if (WallYHit())
	{
		yp = -yp;
		//PlaySound("tennis.wav", NULL, SND_ASYNC);
	}

		x += xp/25;
		y += yp/25;
		z += zp/25;

	debug << "z = " << z << endl;

    if (mx >= (XMAX-0.5f)) mx = XMAX-0.5f,mxp = 0;			//Mouse X check
    if (mx <= (XMIN+0.5f)) mx = XMIN+0.5f,mxp = 0;  
    if (my <= (YMIN+0.5f)) my = YMIN+0.5f, myp = 0;		//Mouse Y check
    if (my >= (YMAX-0.5f)) my = YMAX-0.5f, myp = 0;

    if (cmx >= (XMAX-0.5f)) cmx = XMAX-0.5f,cmxp = 0;
    if (cmx <= (XMIN+0.5f)) cmx = XMIN+0.5f,cmxp = 0;
	if (cmy <= (YMIN+0.5f)) cmy = YMIN+0.5f, cmyp = 0;		//Mouse Y check
    if (cmy >= (YMAX-0.5f)) cmy = YMAX-0.5f, cmyp = 0;
	if (isServed && (dontbounce > 0))
	  dontbounce--;
  }

  glDisable(GL_DEPTH_TEST);
  glDisable(GL_TEXTURE_2D);							// Disable Texture Mapping

  //Ceiling
  glLoadIdentity();
  glColor4f(1,1,1,1);
  glBegin(GL_LINES);
	glVertex3f(XMIN, YMAX, MYPADDLEZ);		//Bottom-left corner
	glVertex3f(XMIN, YMAX, OPPPADDLEZ);		//Top-left corner
	glVertex3f(XMIN, YMAX, OPPPADDLEZ);		//Top-left corner
	glVertex3f(XMAX, YMAX, OPPPADDLEZ);		//Top-right corner
	glVertex3f(XMAX, YMAX, OPPPADDLEZ);		//Top-right corner
	glVertex3f(XMAX, YMAX, MYPADDLEZ);		//Bottom-right corner
	glVertex3f(XMAX, YMAX, MYPADDLEZ);		//Bottom-right corner
	glVertex3f(XMIN, YMAX, MYPADDLEZ);		//Bottom-left corner
  glEnd();

  //Floor
  glLoadIdentity();
  glColor4f(1,1,1,1);
  glBegin(GL_LINES);
	glVertex3f(XMIN, YMIN, MYPADDLEZ);		//Bottom-left corner
	glVertex3f(XMIN, YMIN, OPPPADDLEZ);		//Top-left corner
	glVertex3f(XMIN, YMIN, OPPPADDLEZ);		//Top-left corner
	glVertex3f(XMAX, YMIN, OPPPADDLEZ);		//Top-right corner
	glVertex3f(XMAX, YMIN, OPPPADDLEZ);		//Top-right corner
	glVertex3f(XMAX, YMIN, MYPADDLEZ);		//Bottom-right corner
	glVertex3f(XMAX, YMIN, MYPADDLEZ);		//Bottom-right corner
	glVertex3f(XMIN, YMIN, MYPADDLEZ);		//Bottom-left corner
  glEnd();

  //Wall OPPONENT is standing in
  glLoadIdentity();
  glColor4f(0.2f,0,1,1);
  glBegin(GL_LINES);
	glVertex3f(XMIN, YMIN, OPPPADDLEZ);		//Bottom-left corner
	glVertex3f(XMIN, YMAX, OPPPADDLEZ);		//Top-left corner
	glVertex3f(XMIN, YMAX, OPPPADDLEZ);		//Top-left corner
	glVertex3f(XMAX, YMAX, OPPPADDLEZ);		//Top-right corner
	glVertex3f(XMAX, YMAX, OPPPADDLEZ);		//Top-right corner
	glVertex3f(XMAX, YMIN, OPPPADDLEZ);		//Bottom-right corner
	glVertex3f(XMAX, YMIN, OPPPADDLEZ);		//Bottom-right corner
	glVertex3f(XMIN, YMIN, OPPPADDLEZ);		//Bottom-left corner
  glEnd();

  // OPPONENT'S PADDLE (CYLINDER)	
  glLoadIdentity();									// Reset The View
	glColor3f(1,1,0);
	glBegin(GL_LINES);
		glVertex3f(cmx-0.5f, cmy+0.5f, cmz);			//top-left corner of rectangle paddle
		glVertex3f(cmx+0.5f, cmy+0.5f, cmz);			//top-right corner of rectangle paddle
		glVertex3f(cmx+0.5f, cmy+0.5f, cmz);			//top-right corner of rectangle paddle
		glVertex3f(cmx+0.5f, cmy-0.5f, cmz);			//bottom-right corner of rectangle paddle
		glVertex3f(cmx+0.5f, cmy-0.5f, cmz);			//bottom-right corner of rectangle paddle
		glVertex3f(cmx-0.5f, cmy-0.5f, cmz);			//bottom-left corner of rectangle paddle
		glVertex3f(cmx-0.5f, cmy-0.5f, cmz);			//bottom-left corner of rectangle paddle
		glVertex3f(cmx-0.5f, cmy+0.5f, cmz);			//top-left corner of rectangle paddle
	glEnd();

	 // OPPONENT'S PADDLE GRID VISIBLE WHEN PADDLE IS HIT
  glLoadIdentity();
  glColor4f(1,cmColor,0,1);
  glBegin(GL_LINES);
		glVertex3f(cmx-0.5f, cmy+0.25f, cmz);		//Left-to-right
		glVertex3f(cmx+0.5f, cmy+0.25f, cmz);
		glVertex3f(cmx-0.5f, cmy, cmz);			//Left-to-right
		glVertex3f(cmx+0.5f, cmy, cmz);
		glVertex3f(cmx-0.5f, cmy-0.25f, cmz);		//Left-to-right
		glVertex3f(cmx+0.5f, cmy-0.25f, cmz);
		glVertex3f(cmx-0.25f, cmy-0.5f, cmz);		//Up-to-down
		glVertex3f(cmx-0.25f, cmy+0.5f, cmz);
		glVertex3f(cmx, cmy-0.5f, cmz);			//Up-to-down
		glVertex3f(cmx, cmy+0.5f, cmz);
		glVertex3f(cmx+0.25f, cmy-0.5f, cmz);		//Up-to-down
		glVertex3f(cmx+0.25f, cmy+0.5f, cmz);
  glEnd();

  if (cmColor < 1)
	  cmColor = cmColor + 0.025;

  glEnable(GL_DEPTH_TEST);
	glEnable(GL_TEXTURE_2D);							// Re-enable Texture Mapping

   glLoadIdentity(); 
  glBindTexture(GL_TEXTURE_2D, texture[0]);
  glTranslatef(x,y,z);
 
	glRotatef(xrot,1.0f,0.0f,0.0f);
	glRotatef(zrot,0.0f,0.0f,1.0f);

  // PUCK
	glColor3f(1,1,1);
  gluSphere(quadratic,.25,16,16);				// Draw A Sphere With A Radius Of 0.25 And 16 Longitude And 16 Latitude Segments

  xspeed += zp/5;
  if (xspeed > ABS(zp*5)) xspeed = ABS(zp*5); 
  if (xspeed < -ABS(zp*5)) xspeed = -ABS(zp*5);
  zspeed += xp/5;
  if (zspeed > ABS(xp*5)) zspeed = ABS(xp*5); 
  if (zspeed < -ABS(xp*5)) zspeed = -ABS(xp*5);
 	xspeed *= .99f;
	zspeed *= .99f;
  xrot+=xspeed;
	zrot-=zspeed;
  
  glDisable(GL_DEPTH_TEST);
  glDisable(GL_TEXTURE_2D);							// Disable Texture Mapping
  
  //Our 3D Room

  //Wall player is standing in
  glLoadIdentity();
  glColor4f(0.2f,0,1,1);
  glBegin(GL_LINES);
	glVertex3f(XMIN, YMIN, MYPADDLEZ);		//Bottom-left corner
	glVertex3f(XMIN, YMAX, MYPADDLEZ);		//Top-left corner
	glVertex3f(XMIN, YMAX, MYPADDLEZ);		//Top-left corner
	glVertex3f(XMAX, YMAX, MYPADDLEZ);		//Top-right corner
	glVertex3f(XMAX, YMAX, MYPADDLEZ);		//Top-right corner
	glVertex3f(XMAX, YMIN, MYPADDLEZ);		//Bottom-right corner
	glVertex3f(XMAX, YMIN, MYPADDLEZ);		//Bottom-right corner
	glVertex3f(XMIN, YMIN, MYPADDLEZ);		//Bottom-left corner
  glEnd();

  //Cursor following ball Z position
  glLoadIdentity();
  glColor4f(0,1,0.4f,1);
  glBegin(GL_LINES);
	glVertex3f(XMIN, YMIN, z);		//Bottom-left corner
	glVertex3f(XMIN, YMAX, z);		//Top-left corner
	glVertex3f(XMIN, YMAX, z);		//Top-left corner
	glVertex3f(XMAX, YMAX, z);		//Top-right corner
	glVertex3f(XMAX, YMAX, z);		//Top-right corner
	glVertex3f(XMAX, YMIN, z);		//Bottom-right corner
	glVertex3f(XMAX, YMIN, z);		//Bottom-right corner
	glVertex3f(XMIN, YMIN, z);		//Bottom-left corner
  glEnd();

  // YOUR PADDLE (CYLINDER) //////////
	glLoadIdentity();									// Reset The View   
  glColor3f(1,1,0); 
  glBegin(GL_LINES);
	glVertex3f(mx-0.5f, my+0.5f, mz);			//top-left corner of rectangle paddle
	glVertex3f(mx+0.5f, my+0.5f, mz);			//top-right corner of rectangle paddle
	glVertex3f(mx+0.5f, my+0.5f, mz);			//top-right corner of rectangle paddle
	glVertex3f(mx+0.5f, my-0.5f, mz);			//bottom-right corner of rectangle paddle
	glVertex3f(mx+0.5f, my-0.5f, mz);			//bottom-right corner of rectangle paddle
	glVertex3f(mx-0.5f, my-0.5f, mz);			//bottom-left corner of rectangle paddle
	glVertex3f(mx-0.5f, my-0.5f, mz);			//bottom-left corner of rectangle paddle
	glVertex3f(mx-0.5f, my+0.5f, mz);			//top-left corner of rectangle paddle
  glEnd();

  // YOUR PADDLE GRID VISIBLE WHEN PADDLE IS HIT
  glLoadIdentity();
  glColor4f(1,mColor,0,1);
  glBegin(GL_LINES);
	glVertex3f(mx-0.5f, my+0.25f, mz);		//Left-to-right
	glVertex3f(mx+0.5f, my+0.25f, mz);
	glVertex3f(mx-0.5f, my, mz);			//Left-to-right
	glVertex3f(mx+0.5f, my, mz);
	glVertex3f(mx-0.5f, my-0.25f, mz);		//Left-to-right
	glVertex3f(mx+0.5f, my-0.25f, mz);
	glVertex3f(mx-0.25f, my-0.5f, mz);		//Up-to-down
	glVertex3f(mx-0.25f, my+0.5f, mz);
	glVertex3f(mx, my-0.5f, mz);			//Up-to-down
	glVertex3f(mx, my+0.5f, mz);
	glVertex3f(mx+0.25f, my-0.5f, mz);		//Up-to-down
	glVertex3f(mx+0.25f, my+0.5f, mz);
  glEnd();

  if (mColor < 1)
	  mColor = mColor + 0.025;

	//SCORE 2
	glLoadIdentity();									// Reset The Current Modelview Matrix
	glTranslatef(0.0f,0.0f,-1.5f);						// Move One Unit Into The Screen
	// Pulsing Colors Based On Text Position
	glColor3f(1.000f, 1.000f, 1.000f);
	// Position The Text On The Screen
	glRasterPos2f(0.00f, -0.60f);
 	glPrint(itoa(score2, temp, 10));	// Print GL Text To The Screen

	//SCORE 1
	glLoadIdentity();									// Reset The Current Modelview Matrix
	glTranslatef(0.0f,0.0f,-1.5f);						// Move One Unit Into The Screen
	// Pulsing Colors Based On Text Position
	glColor3f(1.000f, 1.000f, 1.000f);
	// Position The Text On The Screen
	glRasterPos2f(-0.70f, -0.60f);
 	glPrint(itoa(score1, temp, 10));

//  glEnable(GL_LIGHTING);
    glEnable(GL_DEPTH_TEST);
	glEnable(GL_TEXTURE_2D);							// Re-enable Texture Mapping

  Time2 = TimerGetTime()/1000;
  DiffTime = ABS(Time2-Time1);      
  while (DiffTime < .015f) // .015 = 66 frames per second
  {
    Sleep(1);
    Time2 = TimerGetTime()/1000;
    DiffTime = ABS(Time2-Time1);      
  }
  Time1 = TimerGetTime()/1000;

  debug << "dontbounce = " << dontbounce << endl;

  delete [] temp;
    
  return TRUE;										// Keep Going
}

GLvoid KillGLWindow(GLvoid)								// Properly Kill The Window
{
	if (hRC)											// Do We Have A Rendering Context?
	{
		if (!wglMakeCurrent(NULL,NULL))					// Are We Able To Release The DC And RC Contexts?
		{
			MessageBox(NULL,"Release Of DC And RC Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
		}

		if (!wglDeleteContext(hRC))						// Are We Able To Delete The RC?
		{
			MessageBox(NULL,"Release Rendering Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
		}
		hRC=NULL;										// Set RC To NULL
	}

	if (hDC && !ReleaseDC(hWnd,hDC))					// Are We Able To Release The DC
	{
		MessageBox(NULL,"Release Device Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
		hDC=NULL;										// Set DC To NULL
	}

	if (hWnd && !DestroyWindow(hWnd))					// Are We Able To Destroy The Window?
	{
		MessageBox(NULL,"Could Not Release hWnd.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
		hWnd=NULL;										// Set hWnd To NULL
	}

	if (fullscreen)										// Are We In Fullscreen Mode?
	{
		ChangeDisplaySettings(NULL,0);					// If So Switch Back To The Desktop
		ShowCursor(TRUE);								// Show Mouse Pointer
	}
	debug.close();
	WSACleanup();
	KillFont();
}

/*	This Code Creates Our OpenGL Window.  Parameters Are:					*
 *	title			- Title To Appear At The Top Of The Window				*
 *	width			- Width Of The GL Window Or Fullscreen Mode				*
 *	height			- Height Of The GL Window Or Fullscreen Mode			*
 *	bits			- Number Of Bits To Use For Color (8/16/24/32)			*
 *	fullscreenflag	- Use Fullscreen Mode (TRUE) Or Windowed Mode (FALSE)	*/
 
BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag)
{
	GLuint		PixelFormat;			// Holds The Results After Searching For A Match
	HINSTANCE	hInstance;				// Holds The Instance Of The Application
	WNDCLASS	wc;						// Windows Class Structure
	DWORD		dwExStyle;				// Window Extended Style
	DWORD		dwStyle;				// Window Style

	fullscreen=fullscreenflag;			// Set The Global Fullscreen Flag

	hInstance			= GetModuleHandle(NULL);				// Grab An Instance For Our Window
	wc.style			= CS_HREDRAW | CS_VREDRAW | CS_OWNDC;	// Redraw On Size, And Own DC For Window.
	wc.lpfnWndProc		= (WNDPROC) WndProc;					// WndProc Handles Messages
	wc.cbClsExtra		= 0;									// No Extra Window Data
	wc.cbWndExtra		= 0;									// No Extra Window Data
	wc.hInstance		= hInstance;							// Set The Instance
	wc.hIcon			= LoadIcon(NULL, IDI_WINLOGO);			// Load The Default Icon
	wc.hCursor			= LoadCursor(NULL, IDC_ARROW);			// Load The Arrow Pointer
	wc.hbrBackground	= NULL;									// No Background Required For GL
	wc.lpszMenuName		= NULL;									// We Don't Want A Menu
	wc.lpszClassName	= "OpenGL";								// Set The Class Name

	if (!RegisterClass(&wc))									// Attempt To Register The Window Class
	{
		MessageBox(NULL,"Failed To Register The Window Class.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;											// Return FALSE
	}
	
	if (fullscreen)												// Attempt Fullscreen Mode?
	{
		DEVMODE dmScreenSettings;								// Device Mode
		memset(&dmScreenSettings,0,sizeof(dmScreenSettings));	// Makes Sure Memory's Cleared
		dmScreenSettings.dmSize=sizeof(dmScreenSettings);		// Size Of The Devmode Structure
		dmScreenSettings.dmPelsWidth	= width;				// Selected Screen Width
		dmScreenSettings.dmPelsHeight	= height;				// Selected Screen Height
		dmScreenSettings.dmBitsPerPel	= bits;					// Selected Bits Per Pixel
		dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;

		// Try To Set Selected Mode And Get Results.  NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar.
		if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
		{
			// If The Mode Fails, Offer Two Options.  Quit Or Use Windowed Mode.
			if (MessageBox(NULL,"The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?","NeHe GL",MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
			{
				fullscreen=FALSE;		// Windowed Mode Selected.  Fullscreen = FALSE
			}
			else
			{
				// Pop Up A Message Box Letting User Know The Program Is Closing.
				MessageBox(NULL,"Program Will Now Close.","ERROR",MB_OK|MB_ICONSTOP);
				return FALSE;									// Return FALSE
			}
		}
	}

	if (fullscreen)												// Are We Still In Fullscreen Mode?
	{
		dwExStyle=WS_EX_APPWINDOW;								// Window Extended Style
		dwStyle=WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;	// Windows Style
		ShowCursor(FALSE);										// Hide Mouse Pointer
	}
	else
	{
		dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;						// Window Extended Style
		dwStyle=WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;	// Windows Style
	}

	// Create The Window
	if (!(hWnd=CreateWindowEx(	dwExStyle,			// Extended Style For The Window
								"OpenGL",			// Class Name
								title,				// Window Title
								dwStyle,			// Window Style
								0, 0,				// Window Position
								width, height,		// Selected Width And Height
								NULL,				// No Parent Window
								NULL,				// No Menu
								hInstance,			// Instance
								NULL)))				// Dont Pass Anything To WM_CREATE
	{
		KillGLWindow();								// Reset The Display
		MessageBox(NULL,"Window Creation Error.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								// Return FALSE
	}

	static	PIXELFORMATDESCRIPTOR pfd=				// pfd Tells Windows How We Want Things To Be
	{
		sizeof(PIXELFORMATDESCRIPTOR),				// Size Of This Pixel Format Descriptor
		1,											// Version Number
		PFD_DRAW_TO_WINDOW |						// Format Must Support Window
		PFD_SUPPORT_OPENGL |						// Format Must Support OpenGL
		PFD_DOUBLEBUFFER,							// Must Support Double Buffering
		PFD_TYPE_RGBA,								// Request An RGBA Format
		bits,										// Select Our Color Depth
		0, 0, 0, 0, 0, 0,							// Color Bits Ignored
		0,											// No Alpha Buffer
		0,											// Shift Bit Ignored
		0,											// No Accumulation Buffer
		0, 0, 0, 0,									// Accumulation Bits Ignored
		16,											// 16Bit Z-Buffer (Depth Buffer)  
		0,											// No Stencil Buffer
		0,											// No Auxiliary Buffer
		PFD_MAIN_PLANE,								// Main Drawing Layer
		0,											// Reserved
		0, 0, 0										// Layer Masks Ignored
	};
	
	if (!(hDC=GetDC(hWnd)))							// Did We Get A Device Context?
	{
		KillGLWindow();								// Reset The Display
		MessageBox(NULL,"Can't Create A GL Device Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								// Return FALSE
	}

	if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd)))	// Did Windows Find A Matching Pixel Format?
	{
		KillGLWindow();								// Reset The Display
		MessageBox(NULL,"Can't Find A Suitable PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								// Return FALSE
	}

	if(!SetPixelFormat(hDC,PixelFormat,&pfd))		// Are We Able To Set The Pixel Format?
	{
		KillGLWindow();								// Reset The Display
		MessageBox(NULL,"Can't Set The PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								// Return FALSE
	}

	if (!(hRC=wglCreateContext(hDC)))				// Are We Able To Get A Rendering Context?
	{
		KillGLWindow();								// Reset The Display
		MessageBox(NULL,"Can't Create A GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								// Return FALSE
	}

	if(!wglMakeCurrent(hDC,hRC))					// Try To Activate The Rendering Context
	{
		KillGLWindow();								// Reset The Display
		MessageBox(NULL,"Can't Activate The GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								// Return FALSE
	}

	ShowWindow(hWnd,SW_SHOW);						// Show The Window
	SetForegroundWindow(hWnd);						// Slightly Higher Priority
	SetFocus(hWnd);									// Sets Keyboard Focus To The Window
	ReSizeGLScene(width, height);					// Set Up Our Perspective GL Screen

	if (!InitGL())									// Initialize Our Newly Created GL Window
	{
		KillGLWindow();								// Reset The Display
		MessageBox(NULL,"Initialization Failed.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								// Return FALSE
	}

	return TRUE;									// Success
}

LRESULT CALLBACK WndProc(	HWND	hWnd,			// Handle For This Window
							UINT	uMsg,			// Message For This Window
							WPARAM	wParam,			// Additional Message Information
							LPARAM	lParam)			// Additional Message Information
{
	switch (uMsg)									// Check For Windows Messages
	{
		case WM_ACTIVATE:							// Watch For Window Activate Message
		{
			if (!HIWORD(wParam))					// Check Minimization State
			{
				active=TRUE;						// Program Is Active
			}
			else
			{
				active=FALSE;						// Program Is No Longer Active
			}

			return 0;								// Return To The Message Loop
		}

		case WM_SYSCOMMAND:							// Intercept System Commands
		{
			switch (wParam)							// Check System Calls
			{
				case SC_SCREENSAVE:					// Screensaver Trying To Start?
				case SC_MONITORPOWER:				// Monitor Trying To Enter Powersave?
				return 0;							// Prevent From Happening
			}
			break;									// Exit
		}

		case WM_CLOSE:								// Did We Receive A Close Message?
		{
			PostQuitMessage(0);						// Send A Quit Message
			return 0;								// Jump Back
		}

		case WM_KEYDOWN:							// Is A Key Being Held Down?
		{
			keys[wParam] = TRUE;					// If So, Mark It As TRUE
			return 0;								// Jump Back
		}

		case WM_KEYUP:								// Has A Key Been Released?
		{
			keys[wParam] = FALSE;					// If So, Mark It As FALSE
			return 0;								// Jump Back
		}

		case WM_SIZE:								// Resize The OpenGL Window
		{
			ReSizeGLScene(LOWORD(lParam),HIWORD(lParam));  // LoWord=Width, HiWord=Height
			return 0;								// Jump Back
		}
	}

	// Pass All Unhandled Messages To DefWindowProc
	return DefWindowProc(hWnd,uMsg,wParam,lParam);
}

long CNTR = 0;


int WINAPI WinMain(	HINSTANCE	hInstance,			// Instance
					HINSTANCE	hPrevInstance,		// Previous Instance
					LPSTR		lpCmdLine,			// Command Line Parameters
					int			nCmdShow)			// Window Show State
{
	MSG		msg;									// Windows Message Structure
	BOOL	done=FALSE;								// Bool Variable To Exit Loop

    CNTR++;
	//set up debugging output
	debug.open("debug.txt", ios::trunc);
	//initialize random number generator
	srand(time(NULL));
	client_id = rand();

	//initialize networking stuff
	 // Start Winsock up
    WSAData wsaData;
	int nCode;
    if ((nCode = WSAStartup(MAKEWORD(1, 1), &wsaData)) != 0) {
		cerr << "WSAStartup() returned error code " << nCode << "." <<
				endl;
        return 255;
    }


	int nPort = 3030;
	 // Find the server's address
    cout << "Looking up address..." << flush;
    u_long nRemoteAddress = inet_addr("169.254.10.95");//"169.254.192.12");
    if (nRemoteAddress == INADDR_NONE) {
        cerr << endl << "something is fucked here" << 
                endl;
        return 3;
    }

	in_addr Address;
    memcpy(&Address, &nRemoteAddress, sizeof(u_long)); 
    cout << inet_ntoa(Address) << ":" << nPort << endl; 

	 // Connect to the server
    cout << "Connecting to remote host..." << flush;
    sd = EstablishConnection(nRemoteAddress, htons(nPort));
    if (sd == INVALID_SOCKET) {
        cerr << endl << "connection is borked" << 
                endl;
        return 3;
    }


	// Ask The User Which Screen Mode They Prefer
	//if (MessageBox(NULL,"Would You Like To Run In Fullscreen Mode?", "Start FullScreen?",MB_YESNO|MB_ICONQUESTION)==IDNO)
	//{
	//MODIFIED THIS: we always want to be in full screen mode
		fullscreen=TRUE;							// Windowed Mode
//	}

	// Create Our OpenGL Window
	if (!CreateGLWindow("Steve's Pong Mania",800,600,16,fullscreen))
	{
		return 0;									// Quit If Window Was Not Created
	}

	while(!done && !DONE)									// Loop That Runs While done=FALSE
	{
		if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))	// Is There A Message Waiting?
		{
			if (msg.message==WM_QUIT)				// Have We Received A Quit Message?
			{
				done=TRUE;							// If So done=TRUE
			}
			else									// If Not, Deal With Window Messages
			{
				TranslateMessage(&msg);				// Translate The Message
				DispatchMessage(&msg);				// Dispatch The Message
			}
		}
		else										// If There Are No Messages
		{
		   // Draw The Scene.  Watch For ESC Key And Quit Messages From DrawGLScene()
			if ((active && !DrawGLScene()))	// Active?  Was There A Quit Received?
			{			
                  done=TRUE;							// ESC or DrawGLScene Signalled A Quit
			}
			else									// Not Time To Quit, Update Screen
			{
            if (MENU) Menu();            
  			SwapBuffers(hDC);					// Swap Buffers (Double Buffering)
					
				if (keys[VK_ESCAPE] && !esc)
	            {
	              esc=true;
                  menuZ=0;
                  MENU=!MENU;
				  if (newgame)
				  {
					  score1 = 0;
					  score2 = 0;
				  }
	            }
                if (!keys[VK_ESCAPE])
                {
                  esc=false;    
                }

              if (MENU) 
              {

				if (keys[VK_UP] && !up)
	            {
	              //PlaySound("type.wav", NULL, SND_ASYNC);
                  up=true;
                  item--;
                  if (item < 1) item = 3;                 
	            }
                if (!keys[VK_UP])
                {
                  up=false;    
                }
	            if (keys[VK_DOWN] && !dn)
	            {
	              //PlaySound("type.wav", NULL, SND_ASYNC);
                  dn=true;
                  item++;
                  if (item > 3) item = 1;                 
	            }
                if (!keys[VK_DOWN])
                {
                  dn=false;    
                }
                if (keys[VK_RETURN])
                {
                  rn=true;
                  Selection = true;
				  if (PlayAgain){
                    MENU=!MENU;
					if (newgame)
					{
					  score1 = 0;
					  score2 = 0;
					}
				  }
                  else if (Exit)
                    done=true;
                }
                if (!keys[VK_RETURN])
                {
                  rn=false;    
                }

                  
                  switch(item)
                  {
                    case 1: PlayAgain=true, Options=false, Exit=false; break;
                    case 2: PlayAgain=false, Options=true,  Exit=false; break;
                    case 3: PlayAgain=false, Options=false, Exit=true; break;
                  }

  			//SwapBuffers(hDC);					// Swap Buffers (Double Buffering)

              }
              else
              {

                /*if (keys[VK_UP])
				{
					mzp -= .0055;
                    //xspeed-=0.01f;
				}
				if (keys[VK_DOWN])
				{
					mzp += .0055;
				    //xspeed+=0.01f;
				}
				if (keys[VK_RIGHT])
				{
					mxp += .0055;
					//yspeed+=0.01f;
				}
				if (keys[VK_LEFT])
				{
					mxp -= .0055;		
                    //yspeed-=0.01f;
				}*/
				  POINT mouse;
				  GetCursorPos(&mouse);					// Gets The Current Cursor Coordinates (Mouse Coordinates)
				  ScreenToClient(hWnd, &mouse);
				  //GLfloat currentX = mouse.x;
				  //GLfloat currentY = mouse.y;
				GLint viewport[4];
				//GLdouble modelview[16];
				//GLdouble projection[16];
				GLfloat winX, winY;//, winZ;
				//GLdouble posX, posY, posZ;

				//glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
				//glGetDoublev( GL_PROJECTION_MATRIX, projection );
				glGetIntegerv( GL_VIEWPORT, viewport );

				winX = (float)mouse.x;
				winY = (float)viewport[3] - (float)mouse.y;
				//glReadPixels( mouse.x, int(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ );

//				gluUnProject( winX, winY, 1, modelview, projection, viewport, &posX, &posY, &posZ);
				  mx = (winX-300.0f)/100.0f;
				  //gluUnProject( winX, winY, winZ, modelview, projection, viewport, &posX, &posY, &posZ);
				  my = (winY-150.0f)/100.0f;
				  //originX=currentX;
				  //originY=currentY;
                
              }
			}
		}
	}

	// Shutdown
	KillGLWindow();									// Kill The Window
	return (msg.wParam);							// Exit The Program
}
